package yl.hs.bmipfull.service.material.impl;


import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yl.hs.bmipfull.annotations.DBTable;
import yl.hs.bmipfull.daos.material.*;
import yl.hs.bmipfull.pojo.laboratory.RawMaterialAcceptRecordEntity;
import yl.hs.bmipfull.pojo.material.PurchaseReceiptEntity;
import yl.hs.bmipfull.pojo.material.PurchaseSystemLogEntity;
import yl.hs.bmipfull.pojo.material.RawMaterialCateEntity;
import yl.hs.bmipfull.pojo.material.RawMaterialInventoryEntity;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.service.laboratory.IRawMaterialAcceptRecordService;
import yl.hs.bmipfull.service.material.IPurchaseReceiptService;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.utils.datastate.ActionType;
import yl.hs.bmipfull.viewmodels.LoginUser;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;
import yl.hs.bmipfull.viewmodels.SubmitModel;
import yl.hs.bmipfull.viewmodels.finance.OrderState;
import yl.hs.bmipfull.viewmodels.finance.ShipOrderReviewModel;
import yl.hs.bmipfull.viewmodels.finance.ShipOrderSignInfoModel;
import yl.hs.bmipfull.viewmodels.material.FreightReviewModel;
import yl.hs.bmipfull.viewmodels.salemanmage.SetTimeVO;
import yl.hs.bmipfull.viewmodels.salemanmage.TimeGroupVO;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 作用:  采购产品单据信息服务层接口实现<br/>
 * 创建时间: 2021年05月19日 17时26分05秒 <br/>
 *
 * @author 吴高丰
 */
@Service
public class PurchaseReceiptServiceImpl extends PurchaseBaseService implements IPurchaseReceiptService {

    @Autowired
    IRawMaterialInventoryDao inventoryDao;
    @Autowired
    IWarehouseDao warehouseDao;

    @Override
    public Integer restore(String sn, String cause) {
        var order = dao.findBySN(sn);
        order.setState(OrderState.NORMAL.code);
        var result = dao.update(order);
        if(result>0) {
            writeLog(ActionType.RESTORE, sn, "恢复发货单:" + cause, null, PurchaseReceiptEntity.class);
        }
        return result;
    }

    @Override
    public Integer UpdateWarehouse(String sn,String rawinventsn) {
        var result = 0;
        var entity = dao.findBySN(sn);
        var weight = entity.getNetWeight();
        var inventoryold = inventoryDao.findByWHSNAndRmSN(entity.getWarehouseSN(),entity.getRmSN());
        var warehouseold = warehouseDao.findBySN(entity.getWarehouseSN());
        var inventorynow = inventoryDao.findBySN(rawinventsn);
        var warehousenow = warehouseDao.findBySN(inventorynow.getWhSN());
        entity.setWarehouseName(inventorynow.getWhName());
        entity.setWarehouseSN(inventorynow.getWhSN());
        result = result+dao.update(entity);
        inventoryold.setQuantity(inventoryold.getQuantity().subtract(weight));
        inventorynow.setQuantity(inventorynow.getQuantity().add(weight));
        warehouseold.setInventory(warehouseold.getInventory().subtract(weight));
        warehousenow.setInventory(warehousenow.getInventory().subtract(weight));
        result=result+warehouseDao.update(warehousenow);
        result=result+warehouseDao.update(warehouseold);
        result=result+inventoryDao.update(inventorynow);
        result=result+inventoryDao.update(inventoryold);
        if(result>0) {
            writeLog(ActionType.UPDATE, sn, "更改仓位信息" + inventoryold.getWhName()+"->"+inventorynow.getWhName(), null, PurchaseReceiptEntity.class);
        }
        return result;
    }

    @Override
    public List<PurchaseReceiptEntity> averagePriceOfMaterials(PageQuery pageQuery,int rowNum, int page) {
        pageQuery.checkSortSides(PurchaseReceiptEntity.class);
        var result = dao.averagePriceOfMaterials(pageQuery.getQuery());
        return result;
    }

    @Override
    public List<PurchaseReceiptEntity> queryListByContractSn(String contractsn) {
        return dao.queryListByContractSn(contractsn);
    }

    @Override
    public Integer update(PurchaseReceiptEntity entity) {
        return dao.update(entity);
    }

    @Override
    public Integer updateNetWeightBuSN(String sn, BigDecimal blockWeight, BigDecimal orgWeight) {
        var entity = dao.findBySN(sn);
        var newweight = entity.getNetWeight().subtract(blockWeight);
        writeLog(ActionType.UPDATE, entity.getSn(), "更改入库单净重由"+entity.getNetWeight().setScale(2, RoundingMode.DOWN)+"变为"+newweight.setScale(2, RoundingMode.DOWN), Tl.toJson(entity)+",吨包重量为"+blockWeight.setScale(2, RoundingMode.DOWN), PurchaseReceiptEntity.class);
        var result = dao.updateNetWeightBuSN(sn,newweight,blockWeight,orgWeight);
        if(result>0){
           var invent = inventoryDao.findByWHSNAndRmSN(entity.getWarehouseSN(),entity.getRmSN());
           if(invent!=null){
               var quantity = invent.getQuantity();
               invent.setQuantity(invent.getQuantity().subtract(blockWeight));
               inventoryDao.update(invent);
               if(blockWeight.compareTo(new BigDecimal(0))<0){
                   writeLog(ActionType.UPDATE,invent.getSn(),"修改入库单"+entity.getSn()+"，扣重"+blockWeight+",库存增加"+blockWeight.abs()+"由"+quantity+"变为"+invent.getQuantity(),null,RawMaterialInventoryEntity.class);
               }else{
                   writeLog(ActionType.UPDATE,invent.getSn(),"修改入库单"+entity.getSn()+"，扣重"+blockWeight+"库存减少"+blockWeight+"由"+quantity+"变为"+invent.getQuantity(),null,RawMaterialInventoryEntity.class);
               }
           }
           var whouse = warehouseDao.findBySN(entity.getWarehouseSN());
           if(whouse!=null){
               whouse.setInventory(whouse.getInventory().subtract(blockWeight));
               warehouseDao.update(whouse);
           }
        }
        return result;
    }

    @Override
    public List<PurchaseReceiptEntity> queryList(PageQuery pageQuery) throws Exception {
        pageQuery.checkSortSides(PurchaseReceiptEntity.class);
        var states = getStates(pageQuery.getQuery().get("states"));
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), PurchaseReceiptEntity.class);
        return dao.queryList(pageQuery.getQuery(), states,filters);
    }
    private List<Integer> getStates(Object o){
        List<Integer> states = new ArrayList<>();
        if(o instanceof List<?> stateList){
            for (var s:stateList){
                states.add(Tl.getInteger(s));
            }
        }
        return states;
    }
    @Override
    public PageResult<PurchaseReceiptEntity> queryPage(PageQuery pageQuery, int rowNum, int page, String productCateSn) throws Exception {
        pageQuery.checkSortSides(PurchaseReceiptEntity.class);
        pageQuery.getQuery().put("querySkip", (page - 1) * rowNum);
        pageQuery.getQuery().put("pageSize", rowNum);
        PageResult<PurchaseReceiptEntity> result = new PageResult<>(rowNum);
        var filters = SearchFilterEngine.generateQueryList(pageQuery.getFilters(), PurchaseReceiptEntity.class);
        var states = getStates(pageQuery.getQuery().get("states"));
        if (productCateSn != null && !"".equals(productCateSn)) {
            final List<RawMaterialCateEntity> rawMaterialCateEntities = rawMaterialCateDao.queryByProudctCateSN(productCateSn);
            List<String> stringStream = rawMaterialCateEntities.stream().map(RawMaterialCateEntity::getSn).toList();
            if (stringStream.size() == 0) {
                return new PageResult<>(0);
            }
            var map = pageQuery.getQuery();
            map.put("snList", stringStream);
            result.setRecords(dao.queryCountByCondition(map, filters, states));
            result.setPage(page);
            var data = dao.queryPage(map, filters, states);

            result.setData(data);
        } else {
            result.setRecords(dao.queryCountByCondition(pageQuery.getQuery(), filters, states));
            result.setPage(page);
            var data = dao.queryPage(pageQuery.getQuery(), filters, states);
            result.setData(data);
        }
        return result;
    }

    @Override
    public Integer FreightReviewOrders(SubmitModel submitModel) {
        if (submitModel.getSn() != null || !submitModel.getSn().equals("")) {
            var receipt = dao.findBySN(submitModel.getSn());
            FreightReviewModel model = new FreightReviewModel();
            try {
                Tl.getChangeLog(model, submitModel.getData());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            var user = HsApp.getCurrent();
            receipt.setFreightReviewTime(new Date());
            if (model.isReview()) {
                receipt.setFreightReviewPrice(model.getPrice());
                receipt.setFreightReviewAmount(model.getAmount());
                receipt.setFreightReviewRemark(model.getRemark());
                receipt.setFreightState((short) 1);
                receipt.setFreightReviewUserName(user.getUserName());
                receipt.setFreightReviewRemark(model.getRemark());
                writeLog(ActionType.UPDATE, receipt.getSn(), "入库单运费审核", Tl.toJson(receipt), PurchaseReceiptEntity.class);
            } else {
                receipt.setFreightState((short) 0);
                receipt.setFreightReviewPrice(BigDecimal.valueOf(0));
                receipt.setFreightReviewAmount(BigDecimal.valueOf(0));
                receipt.setFreightReviewTime(new Date());
                receipt.setFreightReviewUserSN(user.getUserSN());
                receipt.setFreightReviewUserName(user.getUserName());
                receipt.setFreightReviewRemark(model.getRemark());
                writeLog(ActionType.UPDATE, receipt.getSn(), "入库单取消运费审核", Tl.toJson(receipt), PurchaseReceiptEntity.class);
            }
            return dao.update(receipt);
        }
        return 0;
    }

    @Override
    public Integer updateUnloading(SubmitModel model) {
        var orderSnList =(List<String>) model.getData().get("orders");
        var price = new BigDecimal(model.getData().get("price").toString());
        var state = Integer.valueOf(model.getData().get("unloadingState").toString());
        if(orderSnList.size()>0){
            for (String s : orderSnList) {
                var entity = dao.findBySN(s);
                var ss = dao.updateUnloading(s,price,price.multiply(entity.getNetWeight()),state);
                if(ss>0){
                    writeLog(ActionType.UPDATE, entity.getSn(), "入库单装卸费审核", Tl.toJson(entity), PurchaseReceiptEntity.class);
                }
            }
        }
        return 1;
    }

    @Override
    public PurchaseReceiptEntity queryByTruckPlateByState(String truckPlate) {
        return dao.queryByTruckPlateByState(truckPlate);
    }

    @Override
    public PurchaseReceiptEntity findBySn(String sn) {
        return dao.findBySN(sn);
    }

    @Override
    @Transactional
    public Integer savePurchaseReceipt(Map<String, Object> model, String sn) throws Exception {
        Integer result;
        PurchaseReceiptEntity entity;
        if (Tl.isEmpty(sn)) {
            //执行保存
            entity = new PurchaseReceiptEntity();
            Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            entity.setSn(queryNewSN(PurchaseReceiptEntity.class));
            entity.setOrganizationCode(getDepartSN());
            if(!Tl.isEmpty(entity.getContractSN())){
                var contract=contractDao.findBySN(entity.getContractSN());
                entity.setContractingUnit(contract.getContractingUnit());
            }
            result = dao.insertNew(entity);
            if (result > 0) {
                writeLog(ActionType.CREATE, entity.getSn(), "插入采购产品单据信息信息", Tl.toJson(entity), PurchaseReceiptEntity.class);
            }

        } else {
            //执行修改
            entity = findBySn(sn);
            var backJson = entity.toJson();
            var changeLog = Tl.getChangeLog(entity, model);
            entity.setPYFieldValue();
            if(!Tl.isEmpty(entity.getContractSN())){
                var contract=contractDao.findBySN(entity.getContractSN());
                entity.setContractingUnit(contract.getContractingUnit());
            }
            result = dao.update(entity);
            if (entity.getState() == 1 && entity.getPrintCount()<=1) {
                var ware = rawMaterialInventoryDao.findByWHSNAndRmSN(entity.getWarehouseSN(), entity.getRmSN());
                if (ware != null) {
                    var warenet = ware.getQuantity();
                    var netwigt = entity.getNetWeight();
                    ware.setQuantity(ware.getQuantity().add(netwigt));
                    writeLog(ActionType.UPDATE,ware.getSn(),"保存入库单，库存增加"+netwigt+"由"+warenet+"变为"+ware.getQuantity(),null,RawMaterialInventoryEntity.class);
                    rawMaterialInventoryDao.update(ware);
                }
                var whouse = warehouseDao.findBySN(entity.getWarehouseSN());
                if(whouse!=null){
                    whouse.setInventory(whouse.getInventory().add(entity.getNetWeight()));
                    warehouseDao.update(whouse);
                }
            }else if(entity.getState()==0){
                if(entity.getCheckState()==1){
                    var user=HsApp.getCurrent();
                    RawMaterialAcceptRecordEntity acceptRecordEntity=new RawMaterialAcceptRecordEntity();
                    assert user != null;
                    acceptRecordEntity.setCheckerName(user.getUserName());
                    acceptRecordEntity.setCheckerSN(user.getUserSN());
                    acceptRecordEntity.setRemark(entity.getRemark());
                    acceptRecordEntity.setOrganizationCode(user.getOrganizationCode());
                    acceptRecordEntity.setRmSN(entity.getRmSN());
                    acceptRecordEntity.setTruckPlate(entity.getTruckPlate());
                    acceptRecordEntity.setRmFullName(entity.getRmCate()+"+"+entity.getRmName()+"-"+entity.getRmSpec());
                    acceptRecordEntity.setCheckTime(entity.getCheckTime());
                    acceptRecordEntity.setDeductWeight(entity.getBlockWeight());
                    acceptRecordEntity.setPYFieldValue();
                    acceptRecordEntity.setSupplierSN(entity.getSupplierSN());
                    acceptRecordEntity.setInTime(entity.getInTime());
                    acceptRecordEntity.setChenkLevel((short) 1);
                    acceptRecordService.saveRawMaterialAcceptRecord(acceptRecordEntity.toMap(),"");
                }
            }else if(entity.getState() == -1){
                writeLog(ActionType.INVALID, sn, changeLog, backJson, PurchaseReceiptEntity.class);
            }
            if (result > 0) {
                writeLog(ActionType.UPDATE, sn, changeLog, backJson, PurchaseReceiptEntity.class);
            }
        }
        if (result > 0) {
            saveGS(
                    entity.getSn(),
                    entity.getSupplierName(),
                    String.join(",",
                            entity.getSupplierName(),
                            entity.getTruckPlate(),
                            entity.getRmCate(),
                            entity.getRmName(),
                            entity.getRmSpec(),
                            entity.getBrand(),
                            entity.getWarehouseName(),
                            entity.getRemark()
                    ),
                    entity,
                    HsApp.getCurrent() != null ? HsApp.getCurrent().getUserSN() : null,
                    null
            );
        }
        return result;
    }

    @Override
    @Transactional
    public Integer delete(String[] sn) {
        var result = dao.changeStateBySn(sn, DataState.DELETED.code);
        if (result > 0) {
            writeLog(ActionType.DELETE, sn, PurchaseReceiptEntity.class);
            deleteGs(sn);
        }
        return result;
    }

    @Override
    public List<String> queryAllTruckPlate() {
        return dao.queryAllTruckPlate();
    }

    @Override
    public List<PurchaseReceiptEntity> queryByState(short state, int top, String sort, String key) {
        return dao.queryByState(state, top, sort, key);
    }

    @Override
    public PurchaseReceiptEntity queryByTruckPlate(String truckPlate) {
        return dao.queryByTruckPlate(truckPlate);
    }

    private PurchaseSystemLogEntity getLog(String mainSN, LoginUser user) {
        var log = new PurchaseSystemLogEntity();
        log.setActionType(ActionType.UPDATE.code);
        log.setDataSN(mainSN);
        log.setUserSN(user.getUserSN());
        log.setUserName(user.getUserName());
        log.setHandleTime(new Date());
        DBTable dbTable;
        dbTable = PurchaseReceiptEntity.class.getAnnotation(DBTable.class);
        if (dbTable != null) {
            log.setTypeCode(dbTable.mapCode());
            log.setTypeName(dbTable.disName());
        } else {
            log.setTypeCode("PurchaseReceiptEntity");
            log.setTypeName("原材入库单");
        }
        return log;
    }

    @Override
    public Integer invalidOrder(String sn, String cause) {
        var order = dao.findBySN(sn);
        var state = order.getState();
        if (order != null) {
            order.setState(OrderState.INVALID.code);
            var result = dao.update(order);
            if (result > 0) {
                var user = HsApp.getCurrent();
                assert user != null;
                var log = getLog(sn, user);
                log.setContent(user.getUserName() + "作废了发货单:" + sn + "，原因：" + cause);
                logDao.insertNew(log);
                var inventory = rawMaterialInventoryDao.findByWHSNAndRmSN(order.getWarehouseSN(), order.getRmSN());
                if (inventory != null && state>0) {
                    var quantity = inventory.getQuantity();
                    inventory.setQuantity(inventory.getQuantity().subtract(order.getNetWeight()));
                    rawMaterialInventoryDao.update(inventory);
                    writeLog(ActionType.UPDATE,inventory.getSn(),"作废入库单，库存减少"+order.getNetWeight()+"由"+quantity+"变为"+inventory.getQuantity(),null,RawMaterialInventoryEntity.class);
                }
                var warehouse = warehouseDao.findBySN(order.getWarehouseSN());
                if(warehouse!=null && state>0){
                    warehouse.setInventory(warehouse.getInventory().subtract(order.getNetWeight()));
                    warehouseDao.update(warehouse);
                }
            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer saveReviewFlag(SubmitModel submitModel) throws Exception {
        var order = dao.findBySN(submitModel.getSn());
        if (order != null) {
            var user = HsApp.getCurrent();
            var model = new ShipOrderReviewModel();
            Tl.getChangeLog(model, submitModel.getData());
            assert user != null;
            var logContent = user.getUserName() + "标注了入库单" + order.getSn() + "为" + model.getFlag() + "，" + model.getRemark();
            order.setReviewFlag(model.getFlag());
            order.setReviewRemark(model.getRemark());
            var result = dao.update(order);
            if (result > 0) {
                var log = getLog(order.getSn(), user);
                log.setContent(logContent);
                logDao.insertNew(log);
            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer saveWeightCheck(SubmitModel submitModel) throws Exception {
        var order = dao.findBySN(submitModel.getSn());
        if (order != null) {
            var user = HsApp.getCurrent();
            var model = new ShipOrderSignInfoModel();
            Tl.getChangeLog(model, submitModel.getData());
            assert user != null;
            var logContent = user.getUserName() + "修改了发货单" + order.getSn() + "的数量，从" + order.getQuantity() +
                    "改为" + model.getQuantity() + ",重量从" + model.getNetWeight() + "改为" + order.getNetWeight() + "，修改原因：" + model.getRemark();
            var temps = order.getNetWeight().subtract(model.getNetWeight());
            order.setQuantity(model.getQuantity());
            order.setNetWeight(model.getNetWeight());
            order.setPrice(Tl.getBigDecimal(submitModel.getData().get("price")));
            order.setAmount(Tl.getBigDecimal(submitModel.getData().get("amount")));
            order.setGrossWeight(order.getGrossWeight().subtract(temps));
            order.setReviewFlag(model.getFlag());
            order.setReviewRemark(model.getRemark());
            var result = dao.update(order);
            saveReviewOrders(submitModel);

            if (result > 0) {
                var log = getLog(order.getSn(), user);
                log.setContent(logContent);
                logDao.insertNew(log);

            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer saveReviewOrders(SubmitModel model) throws Exception {
        List<String> orderSnList = new ArrayList<>();
        var orders = model.getData().get("orders");
        if(orders instanceof List<?> snList){
            for (var s : snList){
                orderSnList.add(s.toString());
            }
        }
        var result = 0;
        if (orderSnList.size() > 0) {
            for (String s : orderSnList) {
                var user = HsApp.getCurrent();
                PurchaseReceiptEntity entity;
                var review = false;
                var code = OrderState.NORMAL.code;
                if (model.getData().get("review") != null) {
                    review = Boolean.parseBoolean(model.getData().get("review").toString());
                }
                BigDecimal reviewWeight=BigDecimal.ZERO;
                BigDecimal reviewQuantity=BigDecimal.ZERO;
                BigDecimal reviewPrice=BigDecimal.ZERO;
                if (review) {
                    code = OrderState.REVIEWED.code;
                    entity = findBySn(model.getSn());
                    Tl.getChangeLog(entity,model.getData());
                    reviewWeight=entity.getReviewWeight();
                    reviewPrice=entity.getPrice();
                } else {
                    code = OrderState.NORMAL.code;
                }
                assert user != null;
                result =result + dao.updateOrderToReviewed(s, user.getUserSN(), user.getUserName(), review, code,reviewWeight,reviewQuantity,reviewPrice);
                if (result > 0) {
                    writeOrderLog(review ? ActionType.REVIEWED : ActionType.UNREVIEWED, Arrays.stream(s.split(",")).toList(), user);
                }
            }
            return result;
        }
        return 0;
    }

    @Override
    public Integer changeStateBySN(String[] snList, short state) {
        int result = dao.changeStateBySn(snList, state);
        if (result > 0) {
            forWriteLog(snList, state);
        }
        return result;
    }

    @Override
    public BigDecimal getRmPrice(String contractSn, String rmSn, Date inTime) {
        return dao.getRmPrice(contractSn, rmSn, inTime);
    }

    @Override
    public List<TimeGroupVO> getSetTime() {
        List<SetTimeVO> setTimeList = dao.getSetTime();

        return VoUtil.groupTime(setTimeList);
    }

    @Override
    public boolean checkTruckTempOrderExist(String truck) {

        return dao.findTruckTempOrder(truck)!=null;
    }



    private void writeOrderLog(ActionType action, List<String> orderSNList, LoginUser user) {
        for (String s : orderSNList) {
            var log = getLog(s, user);
            log.setActionType(action.code);
            log.setContent(String.format("%s%s了编号为(%s)的%s信息", user.getUserName(), getActionDesc(action), s, log.getTypeName()));
            logDao.insertNew(log);
        }
    }

    @Override
    public Integer changeInHost(int state, String sn) {
        return dao.updateInHost(Arrays.stream(sn.split(",")).toList(),state);
    }
    @Autowired
    public void setDao(IPurchaseReceiptDao dao) {
        this.dao = dao;
    }
    @Autowired
    public void setRawMaterialCateDao(IRawMaterialCateDao rawMaterialCateDao) {
        this.rawMaterialCateDao = rawMaterialCateDao;
    }
    @Autowired
    public void setRawMaterialInventoryDao(IRawMaterialInventoryDao rawMaterialInventoryDao) {
        this.rawMaterialInventoryDao = rawMaterialInventoryDao;
    }
    @Autowired
    public void setAcceptRecordService(IRawMaterialAcceptRecordService acceptRecordService) {
        this.acceptRecordService = acceptRecordService;
    }
    @Autowired
    public void setContractDao(IPurchaseContractDao contractDao) {
        this.contractDao = contractDao;
    }

    private IPurchaseReceiptDao dao;
    private IRawMaterialCateDao rawMaterialCateDao;
    private IRawMaterialInventoryDao rawMaterialInventoryDao;
    private IRawMaterialAcceptRecordService acceptRecordService;
    private IPurchaseContractDao contractDao;
}